Skip to content

Add private _asyncioEventLoop module#19816

Merged
seanbudd merged 2 commits intonvaccess:masterfrom
bramd:asyncio-event-loop
Mar 23, 2026
Merged

Add private _asyncioEventLoop module#19816
seanbudd merged 2 commits intonvaccess:masterfrom
bramd:asyncio-event-loop

Conversation

@bramd
Copy link
Copy Markdown
Contributor

@bramd bramd commented Mar 19, 2026

Link to issue number:

N/A. This is a follow-up from #19122 (DotPad BLE support), splitting out the asyncio event loop module as requested during review.

Summary of the issue:

NVDA currently has no built-in way to run asyncio coroutines. Components that need async functionality (e.g. BLE communication) require a managed asyncio event loop running on a background thread.

Description of user facing changes:

N/A. This is a developer-facing module only.

Description of developer facing changes:

Added a private _asyncioEventLoop module that provides:

  • initialize() / terminate() — lifecycle management, wired into NVDA core startup/shutdown
  • runCoroutine(coro) — schedule a coroutine on the event loop (fire-and-forget)
  • runCoroutineSync(coro, timeout) — schedule a coroutine and block until completion

The module is prefixed with an underscore to keep it internal to NVDA core and not part of the public add-on API.

Description of development approach:

The asyncio event loop runs on a daemon thread, started during NVDA initialization (after appModuleHandler) and terminated during shutdown (after hwIo). The terminate() function cancels all pending tasks before stopping the loop.

runCoroutineSync wraps asyncio.run_coroutine_threadsafe with optional timeout support and converts asyncio.TimeoutError to the built-in TimeoutError for a cleaner API.

Testing strategy:

6 unit tests covering runCoroutineSync:

  • Returns simple and complex results
  • Propagates exceptions from coroutines
  • Raises TimeoutError when timeout is exceeded
  • Waits indefinitely when no timeout is specified
  • Raises RuntimeError when the event loop is not running

Run with: rununittests.bat -k test_asyncioEventLoop

Known issues with pull request:

The module is marked as private (underscore prefix) intentionally. The API is stable for current internal use, but is not part of NVDA's public API so add-on developers should not depend on it.

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation: N/A
    • Developer / Technical Documentation: N/A
    • Context sensitive help for GUI changes: N/A
  • Testing:
    • Unit tests
    • System (end to end) tests: N/A
    • Manual testing: N/A
  • UX of all users considered: N/A (no user-facing changes)
  • API is compatible with existing add-ons.
  • Security precautions taken.

…round thread

Split from nvaccess#19122. Provides initialize/terminate lifecycle and runCoroutine/runCoroutineSync helpers for scheduling async work from synchronous code. Wired into core startup/shutdown. Includes 6 unit tests.
@bramd bramd force-pushed the asyncio-event-loop branch from cb5ead6 to 13f0d34 Compare March 19, 2026 20:02
@bramd bramd marked this pull request as ready for review March 19, 2026 20:06
@bramd bramd requested a review from a team as a code owner March 19, 2026 20:06
@bramd bramd requested a review from seanbudd March 19, 2026 20:06
Copy link
Copy Markdown
Member

@seanbudd seanbudd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - all the code here looks good, just needs a slight restructure

Comment thread source/_asyncioEventLoop.py Outdated
Comment thread source/_asyncioEventLoop.py Outdated
Comment thread user_docs/en/changes.md Outdated
@seanbudd seanbudd marked this pull request as draft March 20, 2026 02:07
… changes entry

- Convert _asyncioEventLoop.py to _asyncioEventLoop/ package
- __init__.py exposes only initialize() and terminate()
- utils.py contains runCoroutine() and runCoroutineSync()
- Shared mutable state (eventLoop, asyncioThread) in _state.py
- Use triple-quoted docstrings for module-level variable annotations
- Move changes.md entry to correct position in developer changes list
- Update tests to import from utils module directly
@bramd bramd force-pushed the asyncio-event-loop branch from 0d1bf04 to a979fa0 Compare March 22, 2026 14:28
@bramd bramd marked this pull request as ready for review March 22, 2026 14:48
@seanbudd seanbudd merged commit 69c1fa0 into nvaccess:master Mar 23, 2026
41 checks passed
@github-actions github-actions bot added this to the 2026.2 milestone Mar 23, 2026
@seanbudd
Copy link
Copy Markdown
Member

Thanks @bramd - could you open up a PR adding the unit tests from #19122 as well (tests/unit/test_asyncioEventLoop.py)?

@bramd
Copy link
Copy Markdown
Contributor Author

bramd commented Mar 23, 2026

@seanbudd Ah, sorry, forgot to include those, will do

@bramd
Copy link
Copy Markdown
Contributor Author

bramd commented Mar 23, 2026

@seanbudd After closer inspection, the tests in this PR seem to be complete and match the asyncio tests from the previous PR. Are there specific tests you want to see added for the event loop/asyncio code?

Regarding the BLE related tests, I'll do a PR for those as discussed before.

@seanbudd
Copy link
Copy Markdown
Member

Ooops yes my mistake re-checking the diff. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants